# Fri Dec  2 16:05:20 CST 2022

# yum install net-snmp-utils
# pip3 install flask -i https://pypi.tuna.tsinghua.edu.cn/simple

# ipv6: snmpwalk -v1 -c allbest 10.173.28.1 .1.3.6.1.2.1.4.35.1.4
# ipv4: snmpwalk -v1 -c allbest 10.173.28.1 .1.3.6.1.2.1.4.22.1.2
# mask: snmpwalk -v 1 -c allbest 10.173.28.1 .1.3.6.1.2.1.4.20.1.3


import os, time, json;
from collections import defaultdict;
import IPy;

class SnmpServer():

    __obj = None;
    __init_flag = True;

    # Singleton
    def __new__(cls, *args, **kwargs):
        if cls.__obj == None:
            cls.__obj = object.__new__(cls);
        return cls.__obj;

    """
    init mysql config
    -----------------
        config (dict): {
            'version': 1,
            'communication': 'allbest',
            'address': '10.173.28.1',
            'ipv6_oid': '.1.3.6.1.2.1.4.35.1.4',
            'ipv4_oid': '.1.3.6.1.2.1.4.22.1.2',
            'mask_oid': '.1.3.6.1.2.1.4.20.1.3',
        }
    """
    def __init__(self, config):
        if self.__init_flag:
            self.config = config;
            self.__init_flag = False;

    """
    result fun
    -----------------
    data (int|str|dict|list)
    code (int) : status code
    msg  (str) : tips info
    """
    def result(self, data = "", code = 0, msg = "success"):
        result = {
            "code": code,
            "msg": msg,
            "time": int(time.time()),
            "data": data
        }
        return result;


    # get ipv6
    def getSnmpIpv6Address(self):
        try:
            version = self.config['version'];
            communication = self.config['communication'];
            address = self.config['address'];
            oid = self.config['ipv6_oid'];

            awk_1 = "| awk -F ipv6. '{print $2}'";
            awk_2 = "| awk -F '= STRING:' '{print $1, $2}'";
            shell = "snmpwalk -v{0} -c {1} {2} {3}".format(version, communication, address, oid);
            snmpwalk_shell = "{0} {1} {2}".format(shell, awk_1, awk_2);
            snmp_ipv6_address = os.popen(snmpwalk_shell).read();

            data = {};
            for key, val in enumerate(str.splitlines(snmp_ipv6_address)):
                tmp = val.split();
                data[key] = {
                    'ipv6': tmp[0][1:-1],
                    'mac': tmp[1]
                };

            return self.result(data);
        except Exception as e:
            raise Exception(self.result(None, 1, e));


    # get ipv4
    def getSnmpIpv4Address(self):
        try:
            version = self.config['version'];
            communication = self.config['communication'];
            address = self.config['address'];
            oid = self.config['ipv4_oid'];

            awk_1 = "| awk -F ipNetToMediaPhysAddress. '{print $2}'";
            awk_2 = "| awk -F '= STRING:' '{print $1, $2}'";
            shell = "snmpwalk -v{0} -c {1} {2} {3}".format(version, communication, address, oid);
            snmpwalk_shell = "{0} {1} {2}".format(shell, awk_1, awk_2);

            snmp_ipv4_address = os.popen(snmpwalk_shell).read();

            data = {};
            for key, val in enumerate(str.splitlines(snmp_ipv4_address)):
                tmp = val.split();
                data[key] = {
                    'vlan': tmp[0].split(".")[0],
                    'ipv4': tmp[0][tmp[0].find('.') + 1:],
                    'mac': tmp[1]
                };

            return self.result(data);
        except Exception as e:
            raise Exception(self.result(None, 1, e));


    # ip mask
    def getIpMask(self):
        try:
            version = self.config['version'];
            communication = self.config['communication'];
            address = self.config['address'];
            oid = self.config['mask_oid'];

            awk_1 = "| awk -F ipAdEntNetMask. '{print $2}'";
            awk_2 = "| awk -F '= IpAddress:' '{print $1, $2}'";
            shell = "snmpwalk -v{0} -c {1} {2} {3}".format(version, communication, address, oid);
            snmpwalk_shell = "{0} {1} {2}".format(shell, awk_1, awk_2);

            snmp_ip_mask = os.popen(snmpwalk_shell).read();

            data = {};
            for key, val in enumerate(str.splitlines(snmp_ip_mask)):
                tmp = val.split();
                ips = tmp[0].split(".")
                # ips[0] + '.' + ips[1] + '.' + ips[2] + '.0/' + tmp[1]
                data[key] = "{0}.{1}.{2}.0/{3}".format(ips[0], ips[1], ips[2], tmp[1]);

            return self.result(data);
        except Exception as e:
            raise Exception(self.result(None, 1, e));


    # address division
    def addressDivision(self):
        try:
            ip_mask = self.getIpMask()['data'];
            ipv4_add = self.getSnmpIpv4Address()['data'];

            data = defaultdict(dict);
            for key in ip_mask:
                for ip_key in ipv4_add:
                    if ipv4_add[ip_key]['ipv4'] in IPy.IP(ip_mask[key], make_net = 1):
                        data[ip_mask[key]][ip_key] = {
                                'vlan': ipv4_add[ip_key]['vlan'],
                                'ipv4': ipv4_add[ip_key]['ipv4'],
                                'mac': ipv4_add[ip_key]['mac']
                        };

            return self.result(data);
        except Exception as e:
            raise Exception(self.result(None, 1, e));
